home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Toolbox / BigScrolling / Sample.p < prev   
Encoding:
Text File  |  1992-12-01  |  20.5 KB  |  615 lines  |  [TEXT/PJMM]

  1. {    This file has been processed by The THINK Pascal Source Converter, v1.1.2.    }
  2.  
  3. {------------------------------------------------------------------------------}
  4.  
  5.  
  6. {$I-}
  7. program Sample;   {    Segmentation strategy:}
  8.  
  9. uses
  10.     Traps, BigScrolling;
  11. const {}
  12.  
  13.     kNoEvents = 0; {no events mask}
  14.     kMinHeap = 21 * 1024;      {1.01 - kMinSpace - This is the minimum result from PurgeSpace, when called}
  15.        {     at initialization time, for the application to run. This number acts}
  16.      {      as a double-check to insure that there really is enough memory for the}
  17.          {      application to run, including what has been taken up already by}
  18.      {      pre-loaded resources, the scrap, code, and other sundry memory blocks.}
  19.     kMinSpace = 8 * 1024;  {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
  20.     kExtremeNeg = -32768;
  21.     kExtremePos = 32767 - 1; {required for old region bug}
  22.  
  23.  {The following constants are all resource IDs, corresponding to resources in Sample.r.}
  24.     rMenuBar = 128; {application's menu bar}
  25.     rAboutAlert = 128; {about alert}
  26.     rUserAlert = 129; {error user alert}
  27.  
  28.  {The following constants are used to identify menus and their items. The menu IDs}
  29.  {      have an "m" prefix and the item numbers within each menu have an "i" prefix.}
  30.     mApple = 128; {Apple menu}
  31.     iAbout = 1;
  32.     mFile = 129; {File menu}
  33.     iQuit = 1;
  34.     mEdit = 130; {Edit menu}
  35.     iUndo = 1;
  36.     iCut = 3;
  37.     iCopy = 4;
  38.     iPaste = 5;
  39.     iClear = 6;  {1.01 - kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
  40.     kDITop = $0050;
  41.     kDILeft = $0070;
  42. var
  43.        {GInBackground is maintained by our osEvent handling routines. Any part of}
  44.  {      the program can check it to find out if it is currently in the background.}
  45.     gInBackground: BOOLEAN; {maintained by Initialize and DoEvent}
  46.     window: WindowPtr;
  47.     cursorRgn: RgnHandle;  { cursorRgn contains a copy of the last mouseRgn we passed to WaitNextEvent}
  48.  
  49. {$S Main}
  50.  
  51. function IsDAWindow (window: WindowPtr): BOOLEAN;
  52.  
  53.     {Check if a window belongs to a desk accessory.}
  54.  
  55.     begin
  56.         if window = nil then
  57.             IsDAWindow := FALSE
  58.         else {DA windows have negative windowKinds}
  59.             IsDAWindow := (WindowPeek(window)^.windowKind < 0);
  60.     end; {IsDAWindow}
  61.  
  62.     {$S Main}
  63.  
  64. function IsAppWindow (window: WindowPtr): BOOLEAN;
  65.  
  66.     {Check to see if a window belongs to the application. If the window pointer}
  67.     { passed was NIL, then it could not be an application window. WindowKinds}
  68.     { that are negative belong to the system and windowKinds less than userKind}
  69.     { are reserved by Apple except for windowKinds equal to dialogKind, which}
  70.     { mean it is a dialog.}
  71.     { 1.02 - In order to reduce the chance of accidentally treating some window}
  72.  { as an AppWindow that shouldn't be, we'll only return true if the windowkind}
  73.     { is userKind. If you add different kinds of windows to Sample you'll need}
  74.     { to change how this all works.}
  75.  
  76.     begin
  77.         if window = nil then
  78.             IsAppWindow := FALSE
  79.         else {application windows have windowKinds = userKind (8)}
  80.             with WindowPeek(window)^ do
  81.                 IsAppWindow := (windowKind = userKind);
  82.     end; {IsAppWindow}
  83.  
  84.     {$S Main}
  85.  
  86. {$Z+}
  87.  {for trafficlights.p}
  88.  
  89. procedure AlertUser;
  90.  
  91. {Display an alert that tells the user an error occurred, then exit the program.}
  92. { This routine is used as an ultimate bail-out for serious errors that prohibit}
  93. { the continuation of the application. Errors that do not require the termination}
  94. { of the application should be handled in a different manner. Error checking and}
  95. { reporting has a place even in the simplest application. For simplicity, the alert}
  96. { displayed here only says that an error occurred, but not what it was. There are}
  97.     { various methods available for being more specific.}
  98.  
  99.     var
  100.         itemHit: integer;
  101.  
  102.     begin
  103.         SetCursor(arrow);
  104.         itemHit := Alert(rUserAlert, nil);
  105.         ExitToShell;
  106.     end; {AlertUser}
  107.  
  108.     {$S Main}
  109.  
  110. function DoCloseWindow (window: WindowPtr): BOOLEAN;
  111.  
  112.     {Close a window.}
  113.  
  114.     {1.01 - At this point, if there was a document associated with a}
  115.     { window, you could do any document saving processing if it is 'dirty'.}
  116.     { DoCloseWindow would return TRUE if the window actually closes, i.e.,}
  117.     { the user does not cancel from a save dialog. This result is handy when}
  118.     { the user quits an application, but then cancels a save of a document}
  119.     { associated with a window. We also added code to close the application}
  120.   { window since otherwise, the termination routines would never stop looping,}
  121.     { waiting for FrontWindow to return NIL.}
  122.  
  123.     begin
  124.         DoCloseWindow := TRUE;
  125.         if IsDAWindow(window) then
  126.             begin
  127.                 CloseDeskAcc(WindowPeek(window)^.windowKind);
  128.             end
  129.         else if IsAppWindow(window) then
  130.             begin
  131.                 CloseAppWindow(window);
  132.             end
  133.     end; {DoCloseWindow}
  134.  
  135.     {$S Initialize}
  136.  
  137. procedure Initialize;
  138.  
  139.     {Set up the whole world, including global variables, Toolbox managers,}
  140.     { and menus. We also create our one application window at this time.}
  141.  
  142.     { If a failure occurs here, we will consider that the application is in such}
  143.     { bad shape that we should just exit. Your error handling may differ, but}
  144.     { the checks should still be made.}
  145.  
  146.  
  147.     var
  148.         menuBar: Handle;
  149.         window: WindowPtr;
  150.         ignoreError: OSErr;
  151.         total, contig: LongInt;
  152.         ignoreResult: BOOLEAN;
  153.         event: EventRecord;
  154.         count: integer;
  155.  
  156.     begin
  157.         gInBackground := FALSE;
  158.  
  159.         InitGraf(@thePort);
  160.         InitFonts;
  161.         InitWindows;
  162.         InitMenus;
  163.         TEInit;
  164.         InitDialogs(nil);
  165.         InitCursor;
  166.  
  167. {1.01 - We used to make a check for memory at this point by examining ApplLimit,}
  168. {      ApplicZone, and StackSpace and comparing that to the minimum size we told}
  169. {      MultiFinder we needed. This did not work well because it assumed too much about}
  170. {      the relationship between what we asked MultiFinder for and what we would actually}
  171. {      get back, as well as how to measure it. Instead, we will use an alternate}
  172.             {      method comprised of two steps.}
  173.  
  174.  {It is better to first check the size of the application heap against a value}
  175. {      that you have determined is the smallest heap the application can reasonably}
  176. {      work in. This number should be derived by examining the size of the heap that}
  177. {      is actually provided by MultiFinder when the minimum size requested is used.}
  178. {      The derivation of the minimum size requested from MultiFinder is described}
  179. {      in Sample.h. The check should be made because the preferred size can end up}
  180. {      being set smaller than the minimum size by the user. This extra check acts to}
  181.  {     insure that your application is starting from a solid memory foundation.}
  182.  
  183.         if ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap then
  184.             AlertUser;
  185.  
  186.     {Next, make sure that enough memory is free for your application to run. It}
  187. {      is possible for a situation to arise where the heap may have been of required}
  188. {      size, but a large scrap was loaded which left too little memory. To check for}
  189. {      this, call PurgeSpace and compare the result with a value that you have determined}
  190. {      is the minimum amount of free memory your application needs at initialization.}
  191. {      This number can be derived several different ways. One way that is fairly}
  192. {      straightforward is to run the application in the minimum size configuration}
  193. {      as described previously. Call PurgeSpace at initialization and examine the value}
  194. {      returned. However, you should make sure that this result is not being modified}
  195. {      by the scrap's presence. You can do that by calling ZeroScrap before calling}
  196.          {     PurgeSpace. Make sure to remove that call before shipping, though.}
  197.  
  198.         PurgeSpace(total, contig);
  199.         if total < kMinSpace then
  200.             AlertUser;
  201.  
  202. {The extra benefit to waitng until after the Toolbox Managers have been initialized}
  203. {      before checking memory is that we can now give the user an alert to tell him what}
  204. {      happened. Although it is possible that the memory situation could be worsened by}
  205. {      displaying an alert, MultiFinder would gracefully exit the application with}
  206.   {     an informative alert if memory became critical. Here we are acting more}
  207. {      in a preventative manner to avoid future disaster from low-memory problems.}
  208.  
  209.         menuBar := GetNewMBar(rMenuBar); {read menus into menu bar}
  210.         if menuBar = nil then
  211.             AlertUser;
  212.         SetMenuBar(menuBar); {install menus}
  213.         DisposHandle(menuBar);
  214.         AddResMenu(GetMHandle(mApple), 'DRVR'); {add DA names to Apple menu}
  215.         DrawMenuBar;
  216.  
  217. {     InitializeApplication is a call to another unit (BigScrolling.p in this case).  This is}
  218. {     here so you can put any application-specific code where it belongs instead of in the main }
  219. {     program all the time.    }
  220.  
  221.         InitializeApplication; { give some other unit the chance to initialize}
  222. {                                            itself }
  223.  
  224.     end; {Initialize}
  225.  
  226.     {$S Main}
  227.  
  228. procedure Terminate;
  229.  
  230.     {Clean up the application and exits. We close all of the windows so that}
  231.     { they can update their documents, if any.}
  232.  
  233.     {1.01 - If we find out that a cancel has occurred, we won't exit to the}
  234.     { shell, but will return instead.}
  235.  
  236.     var
  237.         aWindow: WindowPtr;
  238.         closed: BOOLEAN;
  239.  
  240.     begin
  241.         closed := TRUE;
  242.         repeat
  243.             aWindow := FrontWindow; {get the current front window}
  244.             if aWindow <> nil then
  245.                 closed := DoCloseWindow(aWindow); {close}
  246. {                    this window}
  247.         until (not closed) | (aWindow = nil); {do all windows}
  248.  
  249. {     TerminateApplication is a call to another unit (TrafficLights.p in the case of Sample).    This is}
  250. {     here so you can put any application-specific code where it belongs instead of in the main }
  251.             {     program all the time.    }
  252.  
  253.         TerminateApplication; { give some other unit the chance to kill itself}
  254. {                                          }
  255.  
  256.         if closed then
  257.             ExitToShell; {exit if no cancellation}
  258.     end; {Terminate}
  259.  
  260.     {$S Main}
  261.  
  262. procedure AdjustMenus;
  263.  
  264.     {Enable and disable menus based on the current state.}
  265.     { The user can only select enabled menu items. We set up all the menu items}
  266.     { before calling MenuSelect or MenuKey, since these are the only times that}
  267.     { a menu item can be selected. Note that MenuSelect is also the only time}
  268.     { the user will see menu items. This approach to deciding what enable/}
  269. { disable state a menu item has the advantage of concentrating all the decision-}
  270. { making in one routine, as opposed to being spread throughout the application.}
  271. { Other application designs may take a different approach that may or may not be}
  272.     { just as valid.}
  273.  
  274. { 9/12/91, (MD) -- Added enabling and disabling page setup and print around DA windows. }
  275.  
  276.     var
  277.         window: WindowPtr;
  278.         menu: MenuHandle;
  279.  
  280.     begin
  281.         window := FrontWindow;
  282.  
  283.         menu := GetMHandle(mEdit);
  284.         if IsDAWindow(window) then
  285.             begin {a desk accessory might need the edit}
  286. {                                                         menu}
  287.                 EnableItem(menu, iUndo);
  288.                 EnableItem(menu, iCut);
  289.                 EnableItem(menu, iCopy);
  290.                 EnableItem(menu, iPaste);
  291.                 EnableItem(menu, iClear);
  292.             end
  293.         else
  294.             begin {but we know we do not}
  295.                 DisableItem(menu, iUndo);
  296.                 DisableItem(menu, iCut);
  297.                 DisableItem(menu, iCopy);
  298.                 DisableItem(menu, iClear);
  299.                 DisableItem(menu, iPaste);
  300.             end;
  301.  
  302.     end; {AdjustMenus}
  303.  
  304.     {$S Main}
  305.  
  306. procedure DoMenuCommand (menuResult: LongInt);
  307.  
  308.     {This is called when an item is chosen from the menu bar (after calling}
  309.     { MenuSelect or MenuKey). It performs the right operation for each command.}
  310.     { It is good to have both the result of MenuSelect and MenuKey go to}
  311.     { one routine like this to keep everything organized.}
  312.  
  313.     var
  314.         menuID: integer; {the ID of the selected menu}
  315.         menuItem: integer; {the item number of the selected menu}
  316.         itemHit: integer;
  317.         daName, newFontName: Str255;
  318.         daRefNum: integer;
  319.         handledByDA: BOOLEAN;
  320.         ignore: BOOLEAN;
  321.         theWindow: windowPtr;     { for making a new window }
  322.  
  323.     begin
  324.         menuID := HiWrd(menuResult); {use built-ins (for efficiency)...}
  325.         menuItem := LoWrd(menuResult); {to get menu item number and menu}
  326. {                                                      number}
  327.         case menuID of
  328.             mApple: 
  329.                 case menuItem of
  330.                     iAbout: {bring up alert for About}
  331.                         itemHit := Alert(rAboutAlert, nil);
  332.                     otherwise
  333.                         begin {all non-About items in this menu are DAs}
  334.                             GetItem(GetMHandle(mApple), menuItem, daName);
  335.                             daRefNum := OpenDeskAcc(daName);
  336.                         end;
  337.                 end;
  338.             mFile: 
  339.                 case menuItem of
  340.                     iQuit: 
  341.                         Terminate;
  342.                 end;
  343.             mEdit: {call SystemEdit for DA editing & MultiFinder}
  344.                 handledByDA := SystemEdit(menuItem - 1); {since we don't do any}
  345. {                                                                            editing}
  346.             otherwise
  347.                 ;        { The System takes care of Apple, Help and Application menus for us when we call}
  348. {                                       MenuSelect, but it's good form to have all cases covered with a statement. }
  349.         end;
  350.         HiliteMenu(0); {unhighlight what MenuSelect (or MenuKey) hilited}
  351.     end; {DoMenuCommand}
  352.  
  353.     {$S Main}
  354.  
  355. procedure DoUpdate (window: WindowPtr);
  356.  
  357.     {This is called when an update event is received for a window.}
  358.     { It calls DrawWindow to draw the contents of an application window.}
  359.     { As an effeciency measure that does not have to be followed, it}
  360.     { calls the drawing routine only if the visRgn is non-empty. This}
  361.     { will handle situations where calculations for drawing or drawing}
  362.     { itself is very time-consuming.}
  363.  
  364.     begin
  365.         if IsAppWindow(window) then
  366.             begin
  367.                 BeginUpdate(window); {sets up the visRgn, clears updateRgn}
  368.                 if not EmptyRgn(window^.visRgn) then {draw if updating needs to be}
  369. {                                                                  done}
  370.                     DrawWindow(window, nil, FALSE, window = FrontWindow); {when we update,}
  371. {                    we're not printing}
  372.                 EndUpdate(window); {restores the visRgn}
  373.             end;
  374.     end; {DoUpdate}
  375.  
  376.     {$S Main}
  377.  
  378. procedure DoActivate (window: WindowPtr; becomingActive: BOOLEAN);
  379.  
  380.     {This is called when a window is activated or deactivated.}
  381.     { In Sample, the Window Manager's handling of activate and}
  382.     { deactivate events is sufficient. Other applications may have}
  383.     { TextEdit records, controls, lists, etc., to activate/deactivate.}
  384.  
  385.     begin
  386.         if IsAppWindow(window) then
  387.             DrawWindow(window, nil, FALSE, becomingActive);
  388.     end; {DoActivate}
  389.  
  390.     {$S Main}
  391.  
  392. procedure GetGlobalMouse (var mouse: point);
  393.  
  394.     {Get the global coordinates of the mouse. When you call OSEventAvail}
  395.     { it will return either a pending event or a null event. In either case,}
  396.     { the where field of the event record will contain the current position}
  397.     { of the mouse in global coordinates and the modifiers field will reflect}
  398.     { the current state of the modifiers. Another way to get the global}
  399.     { coordinates is to call GetMouse and LocalToGlobal, but that requires}
  400.     { being sure that thePort is set to a valid port.}
  401.  
  402.     var
  403.         event: EventRecord;
  404.  
  405.     begin
  406.         if OSEventAvail(kNoEvents, event) then
  407.             ; {we aren't interested in any}
  408. {                                                                 events}
  409.         mouse := event.where; {just the mouse position}
  410.     end;
  411.  
  412.     {$S Main}
  413.  
  414. procedure AdjustCursor (mouse: point);
  415.  
  416. {Change the cursor's shape, depending on its position. This also calculates the region}
  417. { where the current cursor resides (for WaitNextEvent). If the mouse is ever outside of}
  418.  { that region, an event is generated, causing this routine to be called. This}
  419.   { allows us to change the region to the region the mouse is currently in. If}
  420. { there is more to the event than just “the mouse moved”, we get called before the}
  421. { event is processed to make sure the cursor is the right one. In any (ahem) event,}
  422.     { this is called again before we fall back into WNE.}
  423.  
  424.     var
  425.         window: WindowPtr;
  426.         arrowRgn: RgnHandle;
  427.         plusRgn: RgnHandle;
  428.         globalContentRect: Rect;
  429.  
  430.         temp: handle;
  431.  
  432.     begin
  433.         window := FrontWindow; {we only adjust the cursor when we are in}
  434. {                                            front}
  435.         if (not gInBackground) and (not IsDAWindow(window)) then
  436.             begin
  437.                 {calculate regions for different cursor shapes}
  438.                 arrowRgn := NewRgn;
  439.                 plusRgn := NewRgn;
  440.  
  441.                 {start with a big, big rectangular region}
  442.                 {1.01 - changed to kExtremeNeg and kExtremePos for consistency}
  443.                 SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  444.  
  445.                 {calculate plusRgn}
  446. { In previous versions of Sample, this routine was significantly more complicated than}
  447. { it is now.  It used to create a rectangular region based on a window's portRect, intersect }
  448. {it with the visRgn.  Since the visRgn is in local coordinates and the contentRgn is in global}
  449. {coordinates, this used to be a fair amount of calculation.  All of which was unnecessary, }
  450. {because:  a)  We only do this for our frontmost window, which is always completely visible}
  451. {unless we have some kind of floating window in front of it, and b) we can't move the mouse}
  452. {into any part of the content region that's not on-screen.}
  453. {This routine now uses the contentRgn of the frontWindow for the plusRgn, exclusively.}
  454.  
  455.                 if IsAppWindow(window) then
  456.                     CopyRgn(WindowPeek(window)^.contRgn, plusRgn);
  457.  
  458.                 {subtract other regions from arrowRgn}
  459.                 DiffRgn(arrowRgn, plusRgn, arrowRgn);
  460.  
  461.                 {change the cursor and the region parameter}
  462.                 if PtInRgn(mouse, plusRgn) then
  463.                     begin
  464.                         SetCursor(GetCursor(plusCursor)^^);
  465.                         CopyRgn(plusRgn, cursorRgn);
  466.                     end
  467.                 else
  468.                     begin
  469.                         SetCursor(arrow);
  470.                         CopyRgn(arrowRgn, cursorRgn);
  471.                     end;
  472.  
  473.                 {get rid of our local regions}
  474.                 DisposeRgn(arrowRgn);
  475.                 DisposeRgn(plusRgn);
  476.             end;
  477.     end; {AdjustCursor}
  478.  
  479.     {$S Main}
  480.  
  481. procedure DoEvent (event: EventRecord);
  482.  
  483. {Do the right thing for an event. Determine what kind of event it is, and call}
  484.     { the appropriate routines.}
  485.  
  486.     var
  487.         part, err: integer;
  488.         window: WindowPtr;
  489.         hit: BOOLEAN;
  490.         key: CHAR;
  491.         aPoint: point;
  492.  
  493.     begin
  494.         case event.what of
  495.             mouseDown: 
  496.                 begin
  497.                     part := FindWindow(event.where, window);
  498.                     case part of
  499.                         inDesk: 
  500.                             ;
  501.                         inMenuBar: 
  502.                             begin {process the menu command}
  503.                                 AdjustMenus;
  504.                                 DoMenuCommand(MenuSelect(event.where));
  505.                             end;
  506.                         inSysWindow: {let the system handle the mouseDown}
  507.                             SystemClick(event, window);
  508.                         inContent: 
  509.                             if window <> FrontWindow then
  510.                                 begin
  511.                                     SelectWindow(window);
  512.                                 {DoEvent(event);}
  513.                                 {use this line for "do first click"}
  514.                                 end
  515.                             else
  516.                                 DoContentClick(window, event);
  517.                         inDrag: 
  518.                             begin
  519.                                 {pass screenBits.bounds to get all gDevices}
  520.                                 DragWindow(window, event.where, screenBits.bounds);
  521.                                 AdjustCursor(event.where);
  522.                             end;
  523.                         inGrow: 
  524.                             ;
  525.                         inZoomIn, inZoomOut: 
  526.                             ;
  527.                     end;
  528.                 end;
  529.             keyDown, autoKey: 
  530.                 begin {check for menukey equivalents}
  531.                     key := CHR(BAND(event.message, charCodeMask));
  532.                     if BAND(event.modifiers, cmdKey) <> 0 then {Command key down}
  533.                         if event.what = keyDown then
  534.                             begin
  535.                                 AdjustMenus; {enable/disable/check menu items properly}
  536.                                 DoMenuCommand(MenuKey(key));
  537.                             end;
  538.                 end; {call DoActivate with the window and...}
  539.             activateEvt: {TRUE for activate, FALSE for deactivate}
  540.                 DoActivate(WindowPtr(event.message), BAND(event.modifiers, activeFlag) <> 0);
  541.             updateEvt: {call DoUpdate with the window to update}
  542.                 DoUpdate(WindowPtr(event.message));
  543.              {1.01 - It is not a bad idea to at least call DIBadMount in response}
  544.                 {            to a diskEvt, so that the user can format a floppy.}
  545.             diskEvt: 
  546.                 if HiWrd(event.message) <> noErr then
  547.                     begin
  548.                         SetPt(aPoint, kDILeft, kDITop);
  549.                         err := DIBadMount(aPoint, event.message);
  550.                     end;
  551.             osEvt: 
  552.                 case BAND(BRotL(event.message, 8), $FF) of {high byte of message}
  553.                     SuspendResumeMessage: 
  554.                         begin
  555.                             gInBackground := BAND(event.message, resumeFlag) = 0;
  556.                             DoActivate(FrontWindow, not gInBackground);
  557.                         end;
  558.                     mouseMovedMessage: 
  559.                         AdjustCursor(event.where);
  560.                 end;
  561.             otherwise
  562.                 ;
  563.         end;
  564.     end; {DoEvent}
  565.  
  566.     {$S Main}
  567.  
  568. procedure EventLoop;
  569.  
  570.     {Get events forever, and handle them by calling DoEvent.}
  571.     { Get the events by calling WaitNextEvent, if it's available, otherwise}
  572.  { by calling GetNextEvent. Also call AdjustCursor each time through the loop.}
  573.  
  574.     var
  575.         gotEvent: BOOLEAN;
  576.         event: EventRecord;
  577.         mouse: point;
  578.  
  579.     begin
  580.         cursorRgn := NewRgn;
  581.         GetGlobalMouse(mouse);   { find the current mouse position }
  582.         AdjustCursor(mouse);  { set up the cursor once }
  583.         repeat
  584. {put us 'asleep' forever under}
  585. {                                                            MultiFinder}
  586.             gotEvent := WaitNextEvent(everyEvent, event, MAXLONGINT, cursorRgn);
  587.  
  588.             if gotEvent then
  589.                 DoEvent(event);
  590.                 {If you are using modeless dialogs that have editText items,}
  591.          {          you will want to call IsDialogEvent to give the caret a chance}
  592.  {          to blink, even if WNE/GNE returned FALSE. However, check FrontWindow}
  593.                 {            for a non-NIL value before calling IsDialogEvent.}
  594.         until FALSE; {loop forever; we quit through an ExitToShell}
  595.     end; {EventLoop}
  596.  
  597.     {This routine is part of the MPW runtime library. This external}
  598.     { reference to it is done so that we can unload its segment, %A5Init.}
  599.  
  600.     {$S Main}
  601.  
  602. begin
  603.  
  604.         {1.01 - call to ForceEnvirons removed}
  605.         {If you have stack requirements that differ from the default,}
  606.         {      then you could use SetApplLimit to increase StackSpace at }
  607.         {      this point, before calling MaxApplZone.}
  608.  
  609.     MaxApplZone; {expand the heap so code segments load at the top}
  610.  
  611.     Initialize; {initialize the program}
  612.     UnloadSeg(@Initialize); {note that Initialize must not be in Main!}
  613.  
  614.     EventLoop; {call the main event loop}
  615. end.